﻿// 🛡️ Defender On-Demand Scanner (Professional Edition)
// Created by: Justin Linwood Ross (Farmington, Maine) U.S.A.
// Beginning Date: 7-2-2015
// Ending Date: 8-19-2025
// This version includes advanced UI/UX, performance, and error handling enhancements.
// - Theming: Switch between light and dark modes.
// - Advanced Process Manager: Shows user, path (in tooltip), and allows setting priority via context menu.
// - Lazy Loading: Process list loads basic info first, then details, keeping the UI responsive.
// - Robust Error Handling: Uses specific exception types and logs errors to a file.
// - Informative Status Bar: Replaces the simple label with a multi-panel status strip.
// - Logging: Application events and errors are logged to "DefenderUI_Log.txt".
// 🍀 For Text Symbols, Go To: https://www.textsymbols.net 🍀
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Speech.Synthesis;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DefenderUI
{
    public partial class Form1 : Form
    {
        // --- Theme Management ---
        private enum AppTheme { Dark, Light }
        private AppTheme currentTheme = AppTheme.Dark;

        // --- UI Controls ---
        private Label titleLabel;
        private Button selectFilesButton, startScanButton, clearListButton, cancelScanButton, updateDefsButton, removeSelectedButton;
        private ProgressBar scanProgressBar;
        private ListBox filesToScanListBox;
        private ListView resultsListView, processListView;
        private Label filesToScanLabel, resultsLabel, processManagerLabel;
        private ContextMenuStrip resultsContextMenu, processContextMenu; // Process context menu is new
        private StatusStrip statusBar; // statusLabel
        private ToolStripStatusLabel fileStatusLabel, mainStatusLabel; // Panels for the status bar
        private Button themeToggleButton, viewLogButton; // Buttons for new features
        private ToolTip processPathToolTip; // Tooltip for process paths

        // Process Manager Controls
        private Button refreshProcessesButton, terminateProcessButton;

        // --- State Management ---
        private List<string> filePaths;
        private bool isScanning = false;
        private CancellationTokenSource cancellationTokenSource;
        private readonly DefenderScanner scanner;
        private SpeechSynthesizer synthesizer;

        public Form1()
        {
            // Initialize state and components
            filePaths = new List<string>();
            scanner = new DefenderScanner();
            Logger.Log("Application session started."); // Logging
            InitializeCustomComponents();
            InitializeSpeechSynthesizer();

            // Form Properties
            Text = "DefenderUI Pro Scanner & Process Manager";
            Size = new Size(1400, 700);
            MinimumSize = new Size(1200, 600);
            StartPosition = FormStartPosition.CenterScreen;
            ApplyTheme(AppTheme.Dark); // Apply initial theme

            // Event Handlers
            FormClosing += OnFormClosing;
            AllowDrop = true;
            DragEnter += Form1_DragEnter;
            DragDrop += Form1_DragDrop;

            // Initial Checks
            if (!scanner.IsDefenderAvailable)
            {
                string msg = "Windows Defender (MpCmdRun.exe) not found. Scanning is disabled. Please ensure Windows Security is active and updated.";
                MessageBox.Show(msg, "Scanner Not Found", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Logger.Log($"CRITICAL: MpCmdRun.exe not found. Disabling scan features.");
                startScanButton.Enabled = false;
                updateDefsButton.Enabled = false;
            }

            // Asynchronously load the initial process list
            _ = PopulateProcessListAsync();
        }

        #region Initialization and UI Setup

        /// <summary>
        /// Initializes all UI components programmatically.
        /// </summary>
        private void InitializeCustomComponents()
        {
            Font mainFont = new Font("Segoe UI", 10F);
            Font titleFont = new Font("Segoe UI", 14F, FontStyle.Bold);
            Font labelFont = new Font("Segoe UI Semibold", 10F);
            int currentTabIndex = 0;

            // --- Main Title and Buttons ---
            titleLabel = new Label { Text = "🛡️ Defender On-Demand Scanner 🛡️", Font = titleFont, Location = new Point(20, 20), Size = new Size(500, 30), TabIndex = currentTabIndex++ };
            themeToggleButton = new Button { Text = "Toggle Theme", Font = mainFont, Size = new Size(120, 40), Location = new Point(600, 15), FlatStyle = FlatStyle.Flat, TabIndex = currentTabIndex++ };
            themeToggleButton.Click += (s, e) => { currentTheme = (currentTheme == AppTheme.Dark) ? AppTheme.Light : AppTheme.Dark; ApplyTheme(currentTheme); };
            viewLogButton = new Button { Text = "View Log", Font = mainFont, Size = new Size(120, 40), Location = new Point(730, 15), FlatStyle = FlatStyle.Flat, TabIndex = currentTabIndex++ };
            viewLogButton.Click += ViewLogButton_Click;

            // --- Scanner Controls ---
            selectFilesButton = new Button { Text = "Select Files...", Font = mainFont, Size = new Size(130, 40), Location = new Point(20, 60), FlatStyle = FlatStyle.Flat, TabIndex = currentTabIndex++ };
            selectFilesButton.Click += SelectFilesButton_Click;
            removeSelectedButton = new Button { Text = "Remove Selected", Font = mainFont, Size = new Size(130, 40), Location = new Point(160, 60), FlatStyle = FlatStyle.Flat, TabIndex = currentTabIndex++ };
            removeSelectedButton.Click += RemoveSelectedButton_Click;
            startScanButton = new Button { Text = "Start Scan", Font = mainFont, Size = new Size(130, 40), Location = new Point(320, 60), FlatStyle = FlatStyle.Flat, Enabled = false, TabIndex = currentTabIndex++ };
            startScanButton.Click += StartScanButton_Click;
            cancelScanButton = new Button { Text = "Cancel Scan", Font = mainFont, Size = new Size(130, 40), Location = new Point(460, 60), FlatStyle = FlatStyle.Flat, Enabled = false, TabIndex = currentTabIndex++ };
            cancelScanButton.Click += CancelScanButton_Click;
            updateDefsButton = new Button { Text = "Update Definitions", Font = mainFont, Size = new Size(140, 40), Location = new Point(600, 60), FlatStyle = FlatStyle.Flat, TabIndex = currentTabIndex++ };
            updateDefsButton.Click += UpdateDefsButton_Click;
            clearListButton = new Button { Text = "Clear List", Font = mainFont, Size = new Size(130, 40), Location = new Point(750, 60), FlatStyle = FlatStyle.Flat, TabIndex = currentTabIndex++ };
            clearListButton.Click += ClearListButton_Click;

            filesToScanLabel = new Label { Text = "Files Queued for Scanning (or Drag & Drop here)", Font = labelFont, Location = new Point(20, 120), Size = new Size(460, 25) };
            filesToScanListBox = new ListBox { Font = new Font("Consolas", 9F), Location = new Point(20, 150), Size = new Size(460, 400), BorderStyle = BorderStyle.FixedSingle, SelectionMode = SelectionMode.MultiExtended, Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left, ScrollAlwaysVisible = true, TabIndex = currentTabIndex++ };
            filesToScanListBox.KeyDown += FilesToScanListBox_KeyDown;

            resultsLabel = new Label { Text = "Scan Results", Font = labelFont, Location = new Point(500, 120), Size = new Size(460, 25) };
            resultsListView = new ListView { Font = new Font("Segoe UI", 9F), Location = new Point(500, 150), Size = new Size(460, 400), BorderStyle = BorderStyle.FixedSingle, View = View.Details, FullRowSelect = true, OwnerDraw = true, Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left, Scrollable = true, TabIndex = currentTabIndex++ };
            resultsListView.Columns.Add("Status", 80);
            resultsListView.Columns.Add("File Name", 150);
            resultsListView.Columns.Add("Details", 150);
            resultsListView.Columns.Add("Full Path", 300);
            resultsListView.DrawColumnHeader += (s, e) => e.DrawDefault = true;
            resultsListView.DrawSubItem += ResultsListView_DrawSubItem;
            resultsContextMenu = new ContextMenuStrip();
            var openLocationMenuItem = new ToolStripMenuItem("Open File Location");
            openLocationMenuItem.Click += OpenLocationMenuItem_Click;
            resultsContextMenu.Items.Add(openLocationMenuItem);
            resultsListView.ContextMenuStrip = resultsContextMenu;

            // --- Process Manager Controls ---
            int pmX = 980;
            processManagerLabel = new Label { Text = "⚙️ Process Manager ⚙️", Font = titleFont, Location = new Point(pmX, 20), Size = new Size(400, 30) };
            refreshProcessesButton = new Button { Text = "Refresh List", Font = mainFont, Size = new Size(130, 40), Location = new Point(pmX, 60), FlatStyle = FlatStyle.Flat, TabIndex = currentTabIndex++ };
            refreshProcessesButton.Click += async (s, e) => await PopulateProcessListAsync();
            terminateProcessButton = new Button { Text = "Terminate Process", Font = mainFont, Size = new Size(140, 40), Location = new Point(pmX + 140, 60), FlatStyle = FlatStyle.Flat, Enabled = false, TabIndex = currentTabIndex++ };
            terminateProcessButton.Click += TerminateProcessButton_Click;

            processListView = new ListView { Font = new Font("Segoe UI", 9F), Location = new Point(pmX, 150), Size = new Size(380, 400), BorderStyle = BorderStyle.FixedSingle, View = View.Details, FullRowSelect = true, Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right, Scrollable = true, TabIndex = currentTabIndex++ };
            processListView.Columns.Add("Process Name", 150);
            processListView.Columns.Add("PID", 50);
            processListView.Columns.Add("Memory (MB)", 80);
            processListView.Columns.Add("Owner", 150); 
            processListView.SelectedIndexChanged += ProcessListView_SelectedIndexChanged;
            processListView.MouseHover += ProcessListView_MouseHover; 

            processPathToolTip = new ToolTip(); 
            InitializeProcessContextMenu(); 
            processListView.ContextMenuStrip = processContextMenu;

            // --- Bottom Controls ---
            scanProgressBar = new ProgressBar { Location = new Point(20, 570), Size = new Size(1340, 20), Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right };
            statusBar = new StatusStrip
            {
                Location = new Point(0, 638),
                Size = new Size(1400, 22),
                Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right
            };

            fileStatusLabel = new ToolStripStatusLabel($"Files in queue: 0") { BorderSides = ToolStripStatusLabelBorderSides.Right };
            mainStatusLabel = new ToolStripStatusLabel("Ready") { Spring = true, TextAlign = ContentAlignment.MiddleLeft };
            statusBar.Items.AddRange(new ToolStripItem[] { mainStatusLabel, fileStatusLabel });

            Controls.AddRange(new Control[] {
                titleLabel, themeToggleButton, viewLogButton, selectFilesButton, removeSelectedButton, startScanButton, cancelScanButton, updateDefsButton, clearListButton,
                filesToScanLabel, filesToScanListBox, resultsLabel, resultsListView, processManagerLabel, refreshProcessesButton, terminateProcessButton,
                processListView, scanProgressBar, statusBar
            });
        }

        /// <summary>
        /// Initializes the speech synthesizer.
        /// </summary>
        private void InitializeSpeechSynthesizer()
        {
            try
            {
                synthesizer = new SpeechSynthesizer();
                synthesizer.SelectVoiceByHints(VoiceGender.Female, VoiceAge.Adult, 0, new System.Globalization.CultureInfo("en-GB"));
            }
            catch (Exception ex)
            {
                Logger.Log($"Speech synthesizer failed to initialize: {ex.Message}");
                synthesizer = null;
            }
        }

        /// <summary>
        /// Creates the context menu for the process list view.
        /// </summary>
        private void InitializeProcessContextMenu()
        {
            processContextMenu = new ContextMenuStrip();
            var openLocationItem = new ToolStripMenuItem("Open File Location");
            openLocationItem.Click += OpenProcessLocation_Click;

            var propertiesItem = new ToolStripMenuItem("Properties");
            propertiesItem.Click += ShowProcessProperties_Click;

            var priorityMenu = new ToolStripMenuItem("Set Priority");
            foreach (ProcessPriorityClass level in Enum.GetValues(typeof(ProcessPriorityClass)))
            {
                if (level != ProcessPriorityClass.Normal && level != ProcessPriorityClass.Idle && level != ProcessPriorityClass.High && level != ProcessPriorityClass.RealTime && level != ProcessPriorityClass.BelowNormal && level != ProcessPriorityClass.AboveNormal) continue;
                var priorityItem = new ToolStripMenuItem(level.ToString())
                {
                    Tag = level
                };
                priorityItem.Click += SetProcessPriority_Click;
                priorityMenu.DropDownItems.Add(priorityItem);
            }

            processContextMenu.Items.AddRange(new ToolStripItem[] { openLocationItem, propertiesItem, new ToolStripSeparator(), priorityMenu });
            processContextMenu.Opening += ProcessContextMenu_Opening;
        }

        #endregion

        #region Process Manager Logic (Advanced)

        /// <summary>
        /// Asynchronously populates the process list using lazy loading for details.
        /// </summary>
        private async Task PopulateProcessListAsync()
        {
            UpdateStatus("Loading process list...");
            processListView.Items.Clear();
            terminateProcessButton.Enabled = false;

            var processes = await Task.Run(() => Process.GetProcesses().OrderBy(p => p.ProcessName));
            var processInfos = processes.Select(p => new ProcessInfo(p)).ToList();

            var listItems = processInfos.Select(pi => new ListViewItem(new[] { pi.Name, pi.Id.ToString(), pi.Memory, pi.Owner }) { Tag = pi }).ToList();
            processListView.Items.AddRange(listItems.ToArray());
            UpdateStatus("Fetching process details...");

            await Task.Run(() =>
            {
                Parallel.ForEach(listItems, item =>
                {
                    var pi = (ProcessInfo)item.Tag;
                    try
                    {
                        var process = Process.GetProcessById(pi.Id);
                        pi.Memory = $"{(process.WorkingSet64 / 1024.0 / 1024.0):N2}";
                        pi.FullPath = process.MainModule?.FileName ?? "Access Denied";
                        pi.Owner = process.GetProcessOwner();
                        pi.Priority = process.PriorityClass;

                        // Update UI for this specific item on the UI thread
                        this.Invoke((Action)(() => {
                            item.SubItems[2].Text = pi.Memory;
                            item.SubItems[3].Text = pi.Owner;
                        }));
                    }
                    catch { /* Process may have exited, or we lack permissions */ }
                });
            });

            UpdateStatus("Process list updated.");
        }

        /// <summary>
        /// Event handler for terminating a selected process.
        /// </summary>
        private void TerminateProcessButton_Click(object sender, EventArgs e)
        {
            if (processListView.SelectedItems.Count == 0) return;
            var pi = (ProcessInfo)processListView.SelectedItems[0].Tag;

            var confirm = MessageBox.Show($"Are you sure you want to terminate {pi.Name} (PID: {pi.Id})?", "Confirm Termination", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
            if (confirm != DialogResult.Yes) return;

            try
            {
                Process.GetProcessById(pi.Id).Kill();
                Logger.Log($"Terminated process {pi.Name} (PID: {pi.Id}).");
                MessageBox.Show("Process terminated.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
                _ = PopulateProcessListAsync();
            }
            catch (Exception ex) when (ex is Win32Exception || ex is NotSupportedException || ex is InvalidOperationException)
            {
                string errorMsg = $"Failed to terminate process. You may not have the required permissions.\nError: {ex.Message}";
                Logger.Log($"ERROR: Could not terminate process {pi.Name}. Reason: {ex.Message}");
                MessageBox.Show(errorMsg, "Termination Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void ProcessListView_SelectedIndexChanged(object sender, EventArgs e)
        {
            terminateProcessButton.Enabled = processListView.SelectedItems.Count > 0;
        }

        #endregion

        #region Process Context Menu Handlers

        private void ProcessContextMenu_Opening(object sender, CancelEventArgs e)
        {
            if (processListView.SelectedItems.Count == 0)
            {
                e.Cancel = true; // Don't show the menu if no item is selected
                return;
            }

            var pi = (ProcessInfo)processListView.SelectedItems[0].Tag;
            var priorityMenu = (ToolStripMenuItem)processContextMenu.Items[3];
            foreach (ToolStripMenuItem item in priorityMenu.DropDownItems)
            {
                item.Checked = (ProcessPriorityClass)item.Tag == pi.Priority;
            }
        }

        private void OpenProcessLocation_Click(object sender, EventArgs e)
        {
            var pi = (ProcessInfo)processListView.SelectedItems[0].Tag;
            if (File.Exists(pi.FullPath))
            {
                Process.Start("explorer.exe", $"/select,\"{pi.FullPath}\"");
            }
            else
            {
                MessageBox.Show("Cannot open file location. The path is inaccessible or the process has exited.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void ShowProcessProperties_Click(object sender, EventArgs e)
        {
            // This is a more complex P/Invoke, omitted for brevity but this is how it would be called.
            MessageBox.Show("Properties feature requires advanced P/Invoke and is not implemented in this version.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void SetProcessPriority_Click(object sender, EventArgs e)
        {
            var pi = (ProcessInfo)processListView.SelectedItems[0].Tag;
            var newPriority = (ProcessPriorityClass)((ToolStripMenuItem)sender).Tag;

            try
            {
                var process = Process.GetProcessById(pi.Id);
                process.PriorityClass = newPriority;
                pi.Priority = newPriority; // Update our local model
                Logger.Log($"Set priority for {pi.Name} to {newPriority}.");
            }
            catch (Exception ex) when (ex is Win32Exception || ex is InvalidOperationException)
            {
                string errorMsg = $"Failed to set priority. You may not have the required permissions.\nError: {ex.Message}";
                Logger.Log($"ERROR: Could not set priority for {pi.Name}. Reason: {ex.Message}");
                MessageBox.Show(errorMsg, "Priority Change Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void ProcessListView_MouseHover(object sender, EventArgs e)
        {
            var hitTest = processListView.HitTest(processListView.PointToClient(Cursor.Position));
            if (hitTest.Item != null)
            {
                var pi = (ProcessInfo)hitTest.Item.Tag;
                if (pi != null && processPathToolTip.GetToolTip(processListView) != pi.FullPath)
                {
                    processPathToolTip.SetToolTip(processListView, pi.FullPath);
                }
            }
        }

        #endregion

        #region Core Scanner Event Handlers

        private void SelectFilesButton_Click(object sender, EventArgs e)
        {
            using (var ofd = new OpenFileDialog { Title = "Select files to scan", Filter = "All files (*.*)|*.*", Multiselect = true })
            {
                if (ofd.ShowDialog() == DialogResult.OK)
                {
                    AddFilesToScanQueue(ofd.FileNames);
                }
            }
        }

        private async void UpdateDefsButton_Click(object sender, EventArgs e)
        {
            synthesizer?.SpeakAsync("update in progress, please wait");
            SetUIState(true);
            UpdateStatus("Starting definition update...");
            scanProgressBar.Style = ProgressBarStyle.Marquee;
            Logger.Log("Starting signature update.");

            var progress = new Progress<string>(update => UpdateStatus($"Update: {update}"));

            try
            {
                bool success = await scanner.UpdateSignaturesAsync(progress);
                string msg = success ? "✔️ Definitions updated successfully!" : "❌ Definition update failed.";
                UpdateStatus(msg);
                Logger.Log(msg);
            }
            catch (Exception ex)
            {
                UpdateStatus($"❌ Update error: {ex.Message}");
                Logger.Log($"FATAL UPDATE ERROR: {ex.Message}");
            }
            finally
            {
                scanProgressBar.Style = ProgressBarStyle.Continuous;
                scanProgressBar.Value = 0;
                SetUIState(false);
                synthesizer?.SpeakAsync("updates are complete");
            }
        }

        private async void StartScanButton_Click(object sender, EventArgs e)
        {
            if (isScanning || !filePaths.Any()) return;

            cancellationTokenSource = new CancellationTokenSource();
            SetUIState(true);
            resultsListView.Items.Clear();
            scanProgressBar.Value = 0;
            scanProgressBar.Maximum = filePaths.Count;
            Logger.Log($"Starting scan of {filePaths.Count} files.");

            int threatsFound = 0;
            var progress = new Progress<ScanResult>(result =>
            {
                if (result.Status == ScanStatus.ThreatFound)
                {
                    Interlocked.Increment(ref threatsFound);
                    Logger.Log($"Threat '{result.ThreatName}' found in file: {result.FilePath}");
                }
                scanProgressBar.Value++;
                UpdateStatus($"Scanning ({scanProgressBar.Value}/{filePaths.Count})... Threats: {threatsFound}");
                AddResultToListView(result);
            });

            try
            {
                await scanner.ScanFilesAsync(filePaths, progress, cancellationTokenSource.Token);
                string summary = $"Scan complete. Found {threatsFound} threat(s).";
                UpdateStatus(summary);
                Logger.Log(summary);
            }
            catch (OperationCanceledException)
            {
                UpdateStatus("Scan cancelled by user.");
                Logger.Log("Scan was cancelled by the user.");
            }
            finally
            {
                SetUIState(false);
            }
        }

        private void CancelScanButton_Click(object sender, EventArgs e)
        {
            cancellationTokenSource?.Cancel();
        }

        private void ClearListButton_Click(object sender, EventArgs e)
        {
            if (isScanning) return;
            filePaths.Clear();
            UpdateFileList();
            resultsListView.Items.Clear();
            scanProgressBar.Value = 0;
            UpdateStatus("Ready");
        }

        private void RemoveSelectedButton_Click(object sender, EventArgs e)
        {
            if (isScanning || filesToScanListBox.SelectedItems.Count == 0) return;
            var itemsToRemove = filesToScanListBox.SelectedItems.Cast<string>().ToList();
            var fileNamesToRemove = new HashSet<string>(itemsToRemove);
            filePaths = filePaths.Where(path => !fileNamesToRemove.Contains(Path.GetFileName(path))).ToList();
            UpdateFileList();
        }

        private void FilesToScanListBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                RemoveSelectedButton_Click(sender, e);
            }
        }

        private void OnFormClosing(object sender, FormClosingEventArgs e)
        {
            Logger.Log("Application session ended.");
            cancellationTokenSource?.Cancel();
            synthesizer?.Dispose();
        }

        #endregion

        #region Drag and Drop Logic

        private void Form1_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy;
        }

        private async void Form1_DragDrop(object sender, DragEventArgs e)
        {
            if (isScanning) return;

            string[] droppedItems = (string[])e.Data.GetData(DataFormats.FileDrop);
            UpdateStatus("Enumerating dropped files...");

            // Perform file enumeration on a background thread
            var filesToAdd = await Task.Run(() =>
            {
                var files = new List<string>();
                foreach (var item in droppedItems)
                {
                    if (File.Exists(item))
                    {
                        files.Add(item);
                    }
                    else if (Directory.Exists(item))
                    {
                        try
                        {
                            files.AddRange(Directory.GetFiles(item, "*.*", SearchOption.AllDirectories));
                        }
                        catch (UnauthorizedAccessException)
                        {
                            Logger.Log($"Access denied while enumerating directory: {item}");
                        }
                    }
                }
                return files;
            });

            AddFilesToScanQueue(filesToAdd.ToArray());
        }

        #endregion

        #region UI Logic, Theming, and Helpers

        private void ApplyTheme(AppTheme theme)
        {
            var dark = (bg: Color.FromArgb(28, 28, 28), text: Color.White, ctrlBg: Color.FromArgb(45, 45, 48), btn: Color.FromArgb(60, 60, 60));
            var light = (bg: Color.FromArgb(240, 240, 240), text: Color.Black, ctrlBg: Color.White, btn: Color.FromArgb(225, 225, 225));
            var colors = (theme == AppTheme.Dark) ? dark : light;

            BackColor = colors.bg;
            ForeColor = colors.text;

            foreach (Control c in Controls)
            {
                if (c is Button btn) { btn.BackColor = colors.btn; btn.ForeColor = colors.text; btn.FlatAppearance.BorderColor = (theme == AppTheme.Dark) ? Color.Gray : Color.DarkGray; }
                if (c is Label) c.ForeColor = colors.text;
                if (c is ListBox || c is ListView) { c.BackColor = colors.ctrlBg; c.ForeColor = colors.text; }
                if (c is StatusStrip ss) { ss.BackColor = colors.btn; ss.ForeColor = colors.text; }
            }

            startScanButton.BackColor = Color.FromArgb(45, 137, 45); startScanButton.ForeColor = Color.White;
            cancelScanButton.BackColor = Color.FromArgb(179, 57, 57); cancelScanButton.ForeColor = Color.White;
            terminateProcessButton.BackColor = Color.FromArgb(179, 57, 57); terminateProcessButton.ForeColor = Color.White;
        }

        private void ViewLogButton_Click(object sender, EventArgs e)
        {
            try
            {
                string logPath = Logger.GetLogFilePath();
                if (!File.Exists(logPath))
                {
                    MessageBox.Show("Log file has not been created yet.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }
                Process.Start(new ProcessStartInfo(logPath) { UseShellExecute = true });
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Could not open log file.\nError: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void AddFilesToScanQueue(string[] files)
        {
            int initialCount = filePaths.Count;
            filePaths.AddRange(files);
            filePaths = filePaths.Distinct().ToList();
            UpdateFileList();
            UpdateStatus($"{filePaths.Count - initialCount} new file(s) added. Total: {filePaths.Count}");
            Logger.Log($"Added {filePaths.Count - initialCount} files to the queue.");
        }

        private void UpdateFileList()
        {
            filesToScanListBox.Items.Clear();
            filesToScanListBox.Items.AddRange(filePaths.Select(Path.GetFileName).ToArray());
            fileStatusLabel.Text = $"Files in queue: {filePaths.Count}";
            SetUIState(isScanning);
        }

        private void AddResultToListView(ScanResult result)
        {
            var item = new ListViewItem(new[] { result.Status.ToString().ToUpper(), Path.GetFileName(result.FilePath), result.ThreatName ?? "N/A", result.FilePath }) { Tag = result.FilePath };
            resultsListView.Items.Add(item);
            resultsListView.EnsureVisible(resultsListView.Items.Count - 1);
        }

        private void UpdateStatus(string message)
        {
            mainStatusLabel.Text = message;
        }

        private void SetUIState(bool scanning)
        {
            isScanning = scanning;
            cancelScanButton.Enabled = scanning;
            startScanButton.Enabled = !scanning && filePaths.Any() && scanner.IsDefenderAvailable;
            selectFilesButton.Enabled = !scanning;
            removeSelectedButton.Enabled = !scanning && filePaths.Any();
            clearListButton.Enabled = !scanning && filePaths.Any();
            updateDefsButton.Enabled = !scanning && scanner.IsDefenderAvailable;
            refreshProcessesButton.Enabled = !scanning;
            terminateProcessButton.Enabled = !scanning && processListView.SelectedItems.Count > 0;
            AllowDrop = !scanning;
        }

        private void OpenLocationMenuItem_Click(object sender, EventArgs e)
        {
            if (resultsListView.SelectedItems.Count > 0)
            {
                string filePath = resultsListView.SelectedItems[0].Tag as string;
                if (!string.IsNullOrEmpty(filePath) && File.Exists(filePath))
                {
                    Process.Start("explorer.exe", $"/select,\"{filePath}\"");
                }
                else
                {
                    MessageBox.Show("File not found or path is invalid.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void ResultsListView_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
        {
            if (e.ColumnIndex == 0)
            {
                Color textColor;
                switch (e.Item.Text.ToUpper())
                {
                    case "THREATFOUND": textColor = Color.FromArgb(255, 107, 107); break;
                    case "CLEAN": textColor = Color.FromArgb(87, 242, 135); break;
                    default: textColor = Color.FromArgb(255, 216, 107); break;
                }
                e.DrawBackground();
                TextRenderer.DrawText(e.Graphics, e.Item.Text, new Font("Segoe UI", 9F, FontStyle.Bold), e.Bounds, textColor, TextFormatFlags.Left);
            }
            else
            {
                e.DrawDefault = true;
            }
        }

        #endregion
    }
}